/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * PGPCrypterFrame.java
 *
 * Created on 08.09.2008, 00:56:38
 */
package jcrypter.pgp;

import jcrypter.utils.keyfinder.PGPKeyReader;
import jcrypter.*;
import java.io.*;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.SignatureException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import jcrypter.utils.KeyGeneratorFrame;
import jcrypter.utils.keyfinder.KeyFinder;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.openpgp.*;

/**
 *
 * @author uli
 */
public class PGPCrypterFrame extends javax.swing.JFrame
{

    /** Creates new form PGPCrypterFrame */
    public PGPCrypterFrame()
    {
        initComponents();
        //Load PGP keyrings and update the key selection combo box
        KeyFinder kf = new KeyFinder(".pgp", ".asc", new PGPKeyReader)
    (
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        passwordLabel = new javax.swing.JLabel();
        passwordField = new javax.swing.JPasswordField();
        inputLabel = new javax.swing.JLabel();
        plaintextScrollPane = new javax.swing.JScrollPane();
        inputField = new javax.swing.JTextArea();
        decryptCheckbox = new javax.swing.JCheckBox();
        okButton = new javax.swing.JButton();
        ciphertextLabel = new javax.swing.JLabel();
        keyLabel = new javax.swing.JLabel();
        ciphertextScrollPane = new javax.swing.JScrollPane();
        outputField = new javax.swing.JTextArea();
        keyComboBox = new javax.swing.JComboBox();
        menuBar = new javax.swing.JMenuBar();
        fileMenu = new javax.swing.JMenu();
        loadFromFileMenuItem = new javax.swing.JMenuItem();
        saveToFileMenuItem = new javax.swing.JMenuItem();
        pgpMenu = new javax.swing.JMenu();
        generateKeyMenuItem = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("PGP Encryption");

        passwordLabel.setDisplayedMnemonic('p');
        passwordLabel.setText(i18n.getString("PGPCrypterFrame.passwordLabel.text")); // NOI18N

        inputLabel.setDisplayedMnemonic('i');
        inputLabel.setText(i18n.getString("PGPCrypterFrame.inputLabel.text")); // NOI18N

        inputField.setColumns(20);
        inputField.setLineWrap(true);
        inputField.setRows(5);
        plaintextScrollPane.setViewportView(inputField);

        decryptCheckbox.setMnemonic('d');
        decryptCheckbox.setText(i18n.getString("PGPCrypterFrame.decryptCheckbox.text")); // NOI18N

        okButton.setMnemonic('o');
        okButton.setText("OK");
        okButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                okButtonMouseClicked(evt);
            }
        });

        ciphertextLabel.setDisplayedMnemonic('o');
        ciphertextLabel.setText(i18n.getString("PGPCrypterFrame.outputLabel.text")); // NOI18N

        keyLabel.setText(i18n.getString("PGPCrypterFrame.keyLabel.text")); // NOI18N

        outputField.setColumns(20);
        outputField.setEditable(false);
        outputField.setLineWrap(true);
        outputField.setRows(5);
        ciphertextScrollPane.setViewportView(outputField);

        keyComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "None" }));

        fileMenu.setText(i18n.getString("PGPCrypterFrame.fileMenu.text")); // NOI18N

        loadFromFileMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
        loadFromFileMenuItem.setMnemonic('l');
        loadFromFileMenuItem.setText(i18n.getString("PGPCrypterFrame.loadFromFileMenuItem.text")); // NOI18N
        loadFromFileMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                loadFromFileMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(loadFromFileMenuItem);

        saveToFileMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
        saveToFileMenuItem.setMnemonic('s');
        saveToFileMenuItem.setText(i18n.getString("PGPCrypterFrame.saveToFileMenuItem.text")); // NOI18N
        saveToFileMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveToFileMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(saveToFileMenuItem);

        menuBar.add(fileMenu);

        pgpMenu.setText(i18n.getString("PGPCrypterFrame.pgpMenu.text")); // NOI18N

        generateKeyMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_G, java.awt.event.InputEvent.CTRL_MASK));
        generateKeyMenuItem.setText(i18n.getString("PGPCrypterFrame.generateKeyMenuItem.text")); // NOI18N
        generateKeyMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                generateKeyMenuItemActionPerformed(evt);
            }
        });
        pgpMenu.add(generateKeyMenuItem);

        menuBar.add(pgpMenu);

        setJMenuBar(menuBar);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(passwordLabel)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(passwordField, javax.swing.GroupLayout.DEFAULT_SIZE, 301, Short.MAX_VALUE))
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(inputLabel)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                                .addComponent(plaintextScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 322, Short.MAX_VALUE))))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(60, 60, 60)
                        .addComponent(decryptCheckbox)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(okButton, javax.swing.GroupLayout.DEFAULT_SIZE, 253, Short.MAX_VALUE))
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(ciphertextLabel)
                            .addComponent(keyLabel))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(ciphertextScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 317, Short.MAX_VALUE)
                            .addComponent(keyComboBox, 0, 317, Short.MAX_VALUE))))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(inputLabel)
                    .addComponent(plaintextScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 151, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(passwordLabel)
                    .addComponent(passwordField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(decryptCheckbox)
                    .addComponent(okButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(keyComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(keyLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(ciphertextLabel)
                    .addComponent(ciphertextScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 151, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void okButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_okButtonMouseClicked
        encryptAsymmetric();
}//GEN-LAST:event_okButtonMouseClicked

private void loadFromFileMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadFromFileMenuItemActionPerformed
    FileInputStream fin = null;
    try
    {
        fileChooser.showOpenDialog(this);
        File file = fileChooser.getSelectedFile();
        byte[] buffer = new byte[(int) file.length()];
        fin = new FileInputStream(file);
        fin.read(buffer);
        fin.close();
        inputField.setText(new String(buffer));
    }
    catch (IOException ex)
    {
        Logger.getLogger(JCrypterFrame.class.getName()).log(Level.SEVERE, null, ex);
        ex.printStackTrace();
    }
    finally
    {
        try
        {
            fin.close();
        }
        catch (IOException ex)
        {
            Logger.getLogger(JCrypterFrame.class.getName()).log(Level.SEVERE, null, ex);
            ex.printStackTrace();
        }
    }
}//GEN-LAST:event_loadFromFileMenuItemActionPerformed

private void saveToFileMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveToFileMenuItemActionPerformed
    FileOutputStream fout = null;
    try
    {
        fileChooser.showSaveDialog(this);
        File file = fileChooser.getSelectedFile();
        byte[] buffer = outputField.getText().getBytes();
        fout = new FileOutputStream(file);
        fout.write(buffer);
        fout.close();
    }
    catch (IOException ex)
    {
        Logger.getLogger(JCrypterFrame.class.getName()).log(Level.SEVERE, null, ex);
    }
    finally
    {
        try
        {
            fout.close();
        }
        catch (IOException ex)
        {
            Logger.getLogger(JCrypterFrame.class.getName()).log(Level.SEVERE, null, ex);
            ex.printStackTrace();
        }
    }
}//GEN-LAST:event_saveToFileMenuItemActionPerformed

private void generateKeyMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_generateKeyMenuItemActionPerformed
    new PGPKeyGeneratorFrame().setVisible(true);
}//GEN-LAST:event_generateKeyMenuItemActionPerformed

    private static void processLiteralData(PGPLiteralData ld, OutputStream out, PGPOnePassSignature ops) throws IOException, SignatureException, SignatureException
    {
        InputStream unc = ld.getInputStream();
        int ch;
        if (ops == null)
        {
            while ((ch = unc.read()) >= 0)
            {
                out.write(ch);
            }
        }
        else
        {
            while ((ch = unc.read()) >= 0)
            {
                out.write(ch);
                ops.update((byte) ch);
            }
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[])
    {
        java.awt.EventQueue.invokeLater(new Runnable()
        {

            public void run()
            {
                new PGPCrypterFrame().setVisible(true);
            }
        });
    }

    private void encryptAsymmetric()
    {
        try
        {
            if (decryptCheckbox.isSelected())
            {
                //Get text
                InputStream in = new ByteArrayInputStream(inputField.getText().getBytes());
                char[] password = passwordField.getPassword();

                ByteArrayOutputStream out = new ByteArrayOutputStream();

                PGPPublicKeyEncryptedData pbe = null;
                in = PGPUtil.getDecoderStream(in);

                PGPObjectFactory pgpF = new PGPObjectFactory(in);
                PGPEncryptedDataList enc;
                Object o = pgpF.nextObject();

                if (o == null)
                {
                    throw new PGPException("Cannot recognize input data format");
                //
                // the first object might be a PGP marker packet.
                //
                }
                if (o instanceof PGPEncryptedDataList)
                {
                    enc = (PGPEncryptedDataList) o;
                }
                else
                {
                    enc = (PGPEncryptedDataList) pgpF.nextObject();
                }

                //
                // find the secret key
                //
                Iterator encObjects = enc.getEncryptedDataObjects();
                if (!encObjects.hasNext())
                {
                    throw new PGPException("No encrypted data");
                }
                pbe = (PGPPublicKeyEncryptedData) encObjects.next();

                PGPPrivateKey sKey = null;
                System.out.println(Long.toHexString(pbe.getKeyID()));
                PGPSecretKey secretKey = pkr.getSecKeysID().get(pbe.getKeyID());
                if (secretKey == null)
                {
                    throw new IllegalArgumentException("Secret key for message not found.");
                }
                sKey = secretKey.extractPrivateKey(password, "BC");
                //sKey = findSecretKey(it, passwd);

                InputStream clear = pbe.getDataStream(sKey, "BC");

                PGPObjectFactory plainFact = new PGPObjectFactory(clear);

                Object message = plainFact.nextObject();
                Object sigLiteralData = null;
                PGPObjectFactory pgpFact = null;

                if (message instanceof PGPCompressedData)
                {
                    PGPCompressedData cData = (PGPCompressedData) message;
                    pgpFact = new PGPObjectFactory(cData.getDataStream());
                    message = pgpFact.nextObject();
                    if (message instanceof PGPOnePassSignatureList)
                    {
                        sigLiteralData = pgpFact.nextObject();
                    }
                }

                if (message instanceof PGPLiteralData)
                {
                    //Message is just encrypted
                    //processLiteralData((PGPLiteralData) message,out,null);
                    }
                else if (message instanceof PGPOnePassSignatureList)
                {
                    PGPOnePassSignature ops = ((PGPOnePassSignatureList) message).get(0);
                    PGPPublicKey pubKey = pkr.getPubKeysID().get(ops.getKeyID());
                    if (pubKey == null)
                    {
                        System.out.println("Cannot find the public key 0x" + Integer.toHexString((int) ops.getKeyID()).toUpperCase());
                    //... decrypt without checking signature
                    //processLiteralData((PGPLiteralData) sigLiteralData,out,null);
                    }
                    else
                    {
                        System.out.println((String) pubKey.getUserIDs().next());
                        ops.initVerify(pubKey, "BC");
                        //processLiteralData((PGPLiteralData) sigLiteralData,out,ops);
                        PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject();
                    }
                }
                else
                {
                    throw new PGPException("message is not a simple encrypted file - type unknown.");
                }

                if (pbe.isIntegrityProtected())
                {
                    if (!pbe.verify())
                    {
                        throw new PGPException("Message failed integrity check!");
                    }
                }

                outputField.setText(new String(out.toByteArray()));

            }
            else //Encrypt
            {
                //Get the selected public key
                PGPPublicKey pubkey = pkr.getPubKeys().get(keyComboBox.getSelectedItem());
                ByteArrayOutputStream finalOut = new ByteArrayOutputStream();
                OutputStream aOut = new ArmoredOutputStream(finalOut);

                ByteArrayOutputStream bOut = new ByteArrayOutputStream();
                PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedData.BZIP2);
                OutputStreamWriter comWriter = new OutputStreamWriter(comData.open(bOut));
                comWriter.write(inputField.getText());
                comWriter.close();
                comData.close();
                //Do the encryption
                PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(PGPEncryptedData.TWOFISH, true, new SecureRandom(), "BC");
                cPk.addMethod(pubkey);
                byte[] bytes = bOut.toByteArray();
                OutputStream cOut = cPk.open(aOut, bytes.length);
                cOut.write(bytes);
                cOut.close();
                aOut.close();
                //Print the encrypted text into the GUI
                outputField.setText(new String(finalOut.toByteArray()));
            }
        }
        catch (NoSuchProviderException ex)
        {
            Logger.getLogger(PGPCrypterFrame.class.getName()).log(Level.SEVERE, null, ex);
            ex.printStackTrace();
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
        }
        catch (PGPException ex) //Data not decryptible
        {
            JOptionPane.showMessageDialog(this, ex, "PGP Error", JOptionPane.ERROR_MESSAGE);
            ex.printStackTrace();
            ex.getUnderlyingException().printStackTrace();
        }
        catch (IllegalArgumentException ex)
        {
            JOptionPane.showMessageDialog(this, ex, "Argument Error", JOptionPane.ERROR_MESSAGE);
            ex.printStackTrace();
        }
        catch (SecurityException ex)
        {
            JOptionPane.showMessageDialog(this, ex, "Argument Error", JOptionPane.ERROR_MESSAGE);
            ex.printStackTrace();
        }
    }
    
    JFileChooser fileChooser = JCrypterFrame.mainFrame.fileChooser;
    PGPKeyReader pkr = new PGPKeyReader();
    ResourceBundle i18n = ResourceBundle.getBundle("jcrypter/pgp/Bundle");
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel ciphertextLabel;
    private javax.swing.JScrollPane ciphertextScrollPane;
    private javax.swing.JCheckBox decryptCheckbox;
    private javax.swing.JMenu fileMenu;
    private javax.swing.JMenuItem generateKeyMenuItem;
    private javax.swing.JTextArea inputField;
    private javax.swing.JLabel inputLabel;
    private javax.swing.JComboBox keyComboBox;
    private javax.swing.JLabel keyLabel;
    private javax.swing.JMenuItem loadFromFileMenuItem;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JButton okButton;
    private javax.swing.JTextArea outputField;
    private javax.swing.JPasswordField passwordField;
    private javax.swing.JLabel passwordLabel;
    private javax.swing.JMenu pgpMenu;
    private javax.swing.JScrollPane plaintextScrollPane;
    private javax.swing.JMenuItem saveToFileMenuItem;
    // End of variables declaration//GEN-END:variables
}
